<?php

namespace Biz\service\bizActivity;

use Biz\cache\brand\Brand as cBrand;
use Biz\cache\lottery\MijiaSmartKitchenLottery as cMijiaSmartKitchenLottery;
use Biz\model\MijiaSmartKitchen\MiJiaSmartKitchenPrize as mMiJiaSmartKitchenPrize;
use Biz\model\MijiaSmartKitchen\MiJiaSmartKitchenUserLottery as mMiJiaSmartKitchenUserLottery;
use Biz\model\MijiaSmartKitchen\MijiaSmartKitchenWinningRecord as mMijiaSmartKitchenWinningRecord;
use Biz\pockets\constInterface\MjiaActivityConfig;
use Biz\pockets\serviceTrait\_Async;
use Biz\tools\helper\Common;
use Doraemon\cache\Activity\WechatWebLogin as WechatWebLoginCache;
use Doraemon\cache\Queue;
use Doraemon\model\AdmUserType;
use Doraemon\model\Phone;
use Doraemon\service\DingTalkAlert;
use Doraemon\service\Identifyingcode;
use Doraemon\service\User;
use Doraemon\tools\Hhzurl;
use Doraemon\tools\Log;
use Doraemon\tools\SensitiveWord;

class mjLottery implements MjiaActivityConfig
{
    //用户uid
    protected $uid = 0;

    //第三id
    protected $third_id = '';

    //设备id
    protected $did = '';

    //用户ip
    protected $uip = '';

    //平台
    protected $platform = self::ACTIVITY_PLATFORM_DEFAULT;

    //用户唯一标识
    protected $uniq_uid;

    //用户抽奖记录id
    protected $user_lottery_rec_id;

    //抽奖日期
    protected $lottery_date;

    protected $winning_prize = [];

    //中奖
    const WINNING_YES = 1;
    //未中奖
    const WINNING_NO = 0;

    const PLATFORMS = [self::ACTIVITY_PLATFORM_DEFAULT => '好好住App', self::ACTIVITY_PLATFORM_WECHAT => '微信公众号'];

    use _Async;


    public function __construct($uid, $did, $uip, $platform = self::ACTIVITY_PLATFORM_DEFAULT, $third_id = '')
    {
        $this->uid = $uid;
        $this->did = $did;
        $this->uip = $uip;
        $this->platform = $platform;
        $this->third_id = $third_id;
        $this->uniq_uid = $this->platform == self::ACTIVITY_PLATFORM_WECHAT ? $this->third_id : $this->uid;
        $this->lottery_date = date('Y-m-d', time());
    }

    //用户是否登录检查
    private function userCheck()
    {
        if (empty($this->uniq_uid)) {
            throw new \Exception('非法用户请求', self::ERROR_CODE_ILLEGAL_REQUEST);
        }

        if ($this->platform == self::ACTIVITY_PLATFORM_WECHAT) {
            if (!WechatWebLoginCache::isExistWechatUser($this->uniq_uid)) {
                throw new \Exception('未授权的用户请求', self::ERROR_CODE_ILLEGAL_REQUEST);
            }
        }
    }

    //限制单个用户请求频率
    private function requestLimit()
    {
        $lockKey = sprintf("%s%s_%s", cMijiaSmartKitchenLottery::_CACHE_KEY_PREFIX_, 'request', strval($this->uniq_uid));

        if (cBrand::isLock($lockKey, 3)) {
            throw new \Exception("短时间内重复请求！", self::ERROR_CODE_REPEAT_REQUEST);
        }
    }

    //检查活动时间
    private function activityTime()
    {
        $currentTime = time();
        if ($currentTime < strtotime(self::ACTIVITY_START_TIME)) {
            throw new \Exception('活动尚未开始', self::ERROR_CODE_ACTIVITY_NOT_START);
        }
        if ($currentTime > strtotime(self::ACTIVITY_END_TIME)) {
            throw new \Exception('活动已结束', self::ERROR_CODE_ACTIVITY_END);
        }
    }

    //检查用户注册时间
    private function userRegisterTime()
    {
        $aMemberProfile = User::getUserInfo($this->uid);

        if ($aMemberProfile['addtime'] >= strtotime(self::ACTIVITY_MEMBER_ADDTIME_GAP)) {
            throw new \Exception('注册时间不满足中奖要求', self::ERROR_CODE_USER_REGISTER_TIME);
        }
    }

    //过滤b1与批量注册
    private function filterTagB1AndBatch()
    {
        $aMemberQualityInfo = AdmUserType::getByUid($this->uid);
        if ($aMemberQualityInfo) {
            $iMemberQuality = $aMemberQualityInfo['quality'];
            if ($iMemberQuality == AdmUserType::B1) {
                throw new \Exception('b1用户', self::ERROR_CODE_USER_B1);
            }
            $sRemarkIdentify = trim($aMemberQualityInfo['identity_mark']);
            $iPos = strpos($sRemarkIdentify, "批量");
            if ($iPos === false) {
            } else {
                throw new \Exception('批量注册用户', self::ERROR_CODE_USER_BATCH_REGISTER);
            }
        }
    }

    //拦截公司内部uid名单
    private function filterInnerUser()
    {
        $aInnerUids = \Biz\tools\helper\Common::getStaffUids();
        if (in_array($this->uid, $aInnerUids)) {
            throw new \Exception('内部员工', self::ERROR_CODE_INNER_USER);
        }
    }

    //过滤没有绑定手机号的 | 过滤142的手机号
    private function filterPhone()
    {
        $aMemberPhone = Phone::getByUid($this->uid);
        if (null == $aMemberPhone) {
            throw new \Exception('没绑定手机号', self::ERROR_CODE_USER_NOT_BOUND_PHONE);
        }
        if (0 === strpos($aMemberPhone['hidden_phone'], Identifyingcode::DEBUG_PHONE_PREFIX)) {
            throw new \Exception('142测试用户', self::ERROR_CODE_USER_TEST);
        }
    }

    //过滤黑名单设备id
    private function filterDid()
    {
        if (SensitiveWord::checkDidBlack($this->did)) {
            throw new \Exception('设备在黑名单', self::ERROR_CODE_DID_BLACK);
        }
    }

    //用户是否可抽奖
    private function canLottery()
    {
        //判断用户是否满足抽奖条件
        if (mjKitchenHome::getLotteryTimes($this->uid) <= 0) {
            throw new \Exception('用户没有可抽奖次数');
        }

        //查询用户抽奖记录存在则不能抽奖
        if (mMiJiaSmartKitchenUserLottery::hasUserLottery($this->uniq_uid, $this->platform)) {
            throw new \Exception('用户已经抽过奖了');
        }

    }

    //设备是否中奖
    private function isDeviceWinning()
    {
        if ($this->did && mMijiaSmartKitchenWinningRecord::hasDidWinning($this->did)) {
            throw new \Exception('设备已中奖了', self::ERROR_CODE_DEV_HAS_WINNING);
        }
    }

    //用户是否中奖
    private function isUserWinning()
    {
        if (cMijiaSmartKitchenLottery::hasWinnning($this->uniq_uid)) {
            throw new \Exception('已经中奖了', self::ERROR_CODE_USER_HAS_WINNING);
        }
        //数据库二次确认是否已中奖
        if (mMijiaSmartKitchenWinningRecord::hasUserWinning($this->uniq_uid, $this->platform)) {
            throw new \Exception('用户已经中奖了', self::ERROR_CODE_USER_HAS_WINNING);
        }
    }

    //中奖私信
    private function winningMsg()
    {
        if ($this->platform == self::ACTIVITY_PLATFORM_DEFAULT) {

            $prizeImg = self::PRIZE_IMAGES[$this->winning_prize['prize_id']] ?? '';

            $link = Hhzurl::getDomain() . self::WINNING_PRIZE_MSG_LINK;

            $nlink = Common::formatLinkNormalLink($link);

            Queue::insertQueue('queue/im/send', [
                'to_uids' => [$this->uid],
                'msgInfo' => [
                    'send_user' => 12456042, //好好住福利官
                    'con_type' => 2,
                    'content' => json_encode(array(
                        'title' => '恭喜你在「米家智能厨房」活动中抽中大奖啦～',
                        'desc' => '7日内有效，逾期即视为自动放弃奖品。',
                        'cover_img' => $prizeImg,
                        'link' => $nlink,
                    ))
                ]
            ], Queue::QUEUE_DORAEMON);
        }
    }

    //创建用户抽奖记录
    private function createUserLotteryRecord()
    {
        $lotteryTime = date('Y-m-d H:i:s', time());

        $params = [
            $this->uid,
            $this->did,
            $this->uip,
            $lotteryTime,
            $this->third_id,
            $this->platform,
            mMiJiaSmartKitchenUserLottery::WINNING_NO
        ];

        $userLotteryRecId = 0;

        $errData = [];

        $bRet = mMiJiaSmartKitchenUserLottery::action(function () use ($params, &$userLotteryRecId, &$errData) {
            $userLotteryRecId = mMiJiaSmartKitchenUserLottery::add(...$params);
            if (!$userLotteryRecId) {
                $errData = [
                    'msg' => '添加抽奖记录失败',
                    'code' => 0,
                ];
                return false;
            }
            $nRet = mjKitchenHome::expendTime($this->uid);
            if (!$nRet) {
                $errData = [
                    'msg' => '减抽奖次数失败',
                    'code' => 0,
                ];
                return false;
            }
            return true;
        });

        if (!$bRet) {
            $errorMsg = $errData['msg'] ?? '未知异常';
            $errorCode = $errData['code'] ?? 0;
            throw new \Exception($errorMsg, $errorCode);
        }

        $this->user_lottery_rec_id = $userLotteryRecId;

    }

    //执行
    private function exec()
    {
        try {
            //用户校验
            $this->userCheck();

            //限制单个用户请求频率
            $this->requestLimit();

            //判断活动有效期
            $this->activityTime();

            //检查用户是否有抽奖机会，积分满100一次，分享一次
            $this->canLottery();

            //添加抽奖记录
            $this->createUserLotteryRecord();

            if ($this->platform == self::ACTIVITY_PLATFORM_DEFAULT) {

                 //检查用户的注册时间
                 $this->userRegisterTime();

                 //过滤没有绑定手机号的 | 过滤142的手机号
                 $this->filterPhone();

                 //过滤b1与批量注册
                 $this->filterTagB1AndBatch();

                 //过滤已被拉黑的设备id
                 $this->filterDid();

                 //过滤内部员工测试号
                 $this->filterInnerUser();

                 //检查设备是否已中奖
                 $this->isDeviceWinning();

            }

            //检查用户是否已中奖
            $this->isUserWinning();

            //先去redis拿奖品，检查库存、添加抽检记录和中奖记录在一个事务里，更新库存版本号,减可抽奖次数
            $this->winning_prize = $this->doLottery();

            if (!empty($this->winning_prize)) {
                //中奖私信
                $this->winningMsg();

                $todayWinningCount = cMijiaSmartKitchenLottery::dayWinningCount($this->lottery_date);

                $prizeLeftCount = cMijiaSmartKitchenLottery::getPrizePoolCount();

                //钉钉提醒
                $alertMessage = [
                    'msg' => '中奖了',
                    'uid' => $this->uid,
                    'openid' => $this->third_id,
                    'platform' => self::PLATFORMS[$this->platform],
                    'lottery_time' => date('Y-m-d H:i:s'),
                    'win' => true,
                    'winning_status' => '中奖',
                    'prize_name' => $this->winning_prize['prize_name'],
                    'today_winning_count' => $todayWinningCount,
                    'prize_left_count' => $prizeLeftCount,
                    'domain' => Hhzurl::getDomain(),
                ];

            }

            Log::info("米家智能厨房 | 用户中奖 paltform:{$this->platform} uid:{$this->uid} third_id:{$this->third_id} ",
                $this->winning_prize);

        } catch (\Exception $e) {
            $errData = [
                'code' => $e->getCode(),
                'message' => $e->getMessage(),
                'uniq_uid' => $this->uniq_uid,
                'uid' => $this->uid,
                'platform' => $this->platform,
                'lottery_date' => $this->lottery_date,
                'did' => $this->did,
                'ip' => $this->uip,
            ];
            Log::error('米家智能厨房 | 未中奖', $errData);

            $todayWinningCount = cMijiaSmartKitchenLottery::dayWinningCount($this->lottery_date);

            $prizeLeftCount = cMijiaSmartKitchenLottery::getPrizePoolCount();

            $alertMessage = [
                'msg' => $e->getMessage(),
                'uid' => $this->uid,
                'openid' => $this->third_id,
                'platform' => self::PLATFORMS[$this->platform],
                'lottery_time' => date('Y-m-d H:i:s'),
                'win' => false,
                'winning_status' => '未中奖',
                'prize_name' => '',
                'today_winning_count' => $todayWinningCount,
                'prize_left_count' => $prizeLeftCount,
                'domain' => Hhzurl::getDomain(),
            ];
        }

        self::dingAlert($alertMessage);

        return $this->winning_prize;
    }

    /**
     * 抽奖
     * @return array
     * @throws \Exception
     */
    private function doLottery()
    {
        $winningPrize = $this->getPrize();

        $prizeId = $winningPrize['prize_id'];

        $prizeName = $winningPrize['prize_name'];

        $expInfo = [];

        //中奖操作事务操作
        $result = mMiJiaSmartKitchenPrize::action(function () use ($prizeId, $prizeName, &$expInfo) {

            //再次从数据库中核对今日中奖数量
            $todayWinningCount = mMijiaSmartKitchenWinningRecord::todayWinningCount($this->lottery_date);
            if ($todayWinningCount >= self::DAY_PRIZE_COUNT[$this->lottery_date]) {
                $expInfo = [
                    'msg' => "今日{$this->lottery_date}抽奖数量已满",
                    'code' => 0,
                ];
                return false;
            }

            //查询奖品信息和奖品库存
            $prizeInfo = mMiJiaSmartKitchenPrize::dataSelectInfo([
                'id' => $prizeId,
                'stock[>]' => 0,
                'data_status' => mMiJiaSmartKitchenPrize::STATUS_NORMAL
            ]);

            if (empty($prizeInfo)) {
                $expInfo = [
                    'msg' => "奖品不存在或者没库存了，奖品ID：$prizeId",
                    'code' => 0,
                ];
                return false;
            }

            $stock = $prizeInfo['stock'];

            $version = $prizeInfo['stock_version'];

            //更新奖品库存
            $bRet = mMiJiaSmartKitchenPrize::dePrizeStock($prizeId, $stock, $version);
            if (!$bRet) {
                $expInfo = [
                    'msg' => "奖品减库存失败，奖品ID：$prizeId 库存：$stock 版本号：$version",
                    'code' => 0,
                ];
                return false;
            }

            $winningTimeStamp = time();
            $winningTime = date('Y-m-d H:i:s', $winningTimeStamp);
            $winningDate = date('Y-m-d', $winningTimeStamp);

            //更新抽奖记录状态为中奖
            $bRet = mMiJiaSmartKitchenUserLottery::dataUpdate(
                [
                    'winning' => mMiJiaSmartKitchenUserLottery::WINNING_YES,
                    'update_time' => $winningTime,
                ],
                [
                    'id' => $this->user_lottery_rec_id
                ]
            );
            if (!$bRet) {
                $expInfo = [
                    'msg' => "更新抽奖记录为中奖状态失败，中奖记录ID:{$this->user_lottery_rec_id}",
                    'code' => 0,
                ];
                return false;
            }

            //添加中奖记录
            $params = [
                $this->user_lottery_rec_id,
                $this->did,
                $this->uid,
                $prizeId,
                $prizeName,
                $winningDate,
                $this->third_id,
                $this->platform
            ];
            $bRet = mMijiaSmartKitchenWinningRecord::add(...$params);
            if (!$bRet) {
                $expInfo = [
                    'msg' => "添加中奖记录失败",
                    'code' => 0,
                ];
                return false;
            }

            return true;
        });

        if (!$result) {
            Log::error('中奖事务处理失败Sql', [
                'mMiJiaSmartKitchenPrize' => mMiJiaSmartKitchenPrize::log(),
                'mMiJiaSmartKitchenUserLottery' => mMiJiaSmartKitchenUserLottery::log(),
                'mMijiaSmartKitchenWinningRecord' => mMijiaSmartKitchenWinningRecord::log()
            ]);
            $errMsg = empty($expInfo) ? '中奖事务处理失败' : $expInfo['msg'];

            //奖品重新放入奖池
            cMijiaSmartKitchenLottery::setPrizePool([$winningPrize]);

            throw new \Exception($errMsg, self::ERROR_CODE_WINING_TRANS_FAIL);
        }

        //今日中奖计数
        cMijiaSmartKitchenLottery::incDayWinningCount($this->lottery_date);

        //添加到中奖用户集合中
        cMijiaSmartKitchenLottery::addWinningUser($this->uniq_uid);

        return $winningPrize;

    }

    /**
     * 从奖池中抽取一个奖品
     * @return array
     * @throws \Exception
     */
    private function getPrize()
    {
        $winningOdds = mt_rand(1, 100);

        if ($winningOdds > self::ACTIVITY_WINNING_ODDS) {
            throw new \Exception('未中奖,概率不够');
        }

        $todayWinningCount = cMijiaSmartKitchenLottery::dayWinningCount($this->lottery_date);

        if ($todayWinningCount >= self::DAY_PRIZE_COUNT[$this->lottery_date]) {
            throw new \Exception('今日奖品已抽完');
        }

        $prize = cMijiaSmartKitchenLottery::getOnePrize();

        if (empty($prize)) {
            throw new \Exception('奖品池空了');
        }

        return $prize;

    }

    //抽奖结果返回
    public function lottery()
    {
        $returnData = [
            'status' => self::WINNING_NO,
            'message' => '很遗憾与奖品擦肩而过！',
            'prize' => [],
        ];

        $this->exec();

        if (empty($this->winning_prize)) {
            return $returnData;
        }

        $prizeImg = self::PRIZE_IMAGES[$this->winning_prize['prize_id']] ?? '';
        $winImage = self::WIN_IMAGES[$this->winning_prize['prize_id']] ?? '';

        $returnData = [
            'status' => self::WINNING_YES,
            'message' => '恭喜你，中奖了！',
            'prize' => [
                'prize_id' => $this->winning_prize['prize_id'],
                'prize_name' => $this->winning_prize['prize_name'],
                'prize_img' => $prizeImg,
                'prize_win_img' => $winImage,
            ],
        ];

        return $returnData;

    }


    /**
     * 异步发送钉钉提醒
     * @param $message
     * @return void
     */
    public static function dingAlert($message)
    {
        self::_async($message);
    }

    public static function _async_dingAlert($message)
    {
        $accessToken = $message['win'] ? DingTalkAlert::MIJIA_WIN : DingTalkAlert::MIJIA_NOT_WIN;

        $msg = <<<MSG
- 抽奖结果：**{$message['msg']}**
- 抽奖平台: **{$message['platform']}**
- UID: **{$message['uid']}**
- OpenID: **{$message['openid']}**
- 抽奖时间: **{$message['lottery_time']}**
- 中奖状态: **{$message['winning_status']}**
- 奖品名称: **{$message['prize_name']}** 
- 今日已抽出奖品数量: **{$message['today_winning_count']}**
- 奖池剩余奖品数量: **{$message['prize_left_count']}**
- 域名: **{$message['domain']}**
MSG;
        DingTalkAlert::sendMarkdownMsg($accessToken, $message['msg'], $msg, true);
    }

}